In recent times, React has shifted its recommendation from using create-react-app (CRA) as the starting point for new projects. Instead, it now encourages developers to use a framework for most projects. However, for smaller projects, a full-fledged framework might not be necessary. In such cases, Vite) emerges as a promising option. Vite is not a framework like Next.js or Remix, but it offers several features that make it an excellent choice for small projects, such as personal portfolios, like my portfolio. In this blog post, we will walk you through the steps to migrate from create-react-app to Vite for your next project.
Migration steps
These migration steps assume that we have a CRA project with Typescript.
- Removing CRA
- Installing Vite dependencies
- Moving index.html
- Adding vite.config.ts
- Adding vite-env.d.ts
- Adding vite scripts
- Fixing tsconfig.json
- Migrating from Jest to Vitest
- Extra
Step 1 - Removing CRA
The first step is to uninstall create-react-app from your project.
npm uninstall react-scripts
Step 2 - Installing Vite dependencies
Next, install the required dependencies for Vite.
npm install vite @vitejs/plugin-react-swc vite-tsconfig-paths vite-plugin-svgr
Note: Depending on your specific needs, you can choose a different plugin from the official Vite plugins documentation.
Step 3 - Moving index.html
create-react-app uses public/index.html as the default entry point, while Vite looks for index.html at the root level. To make the transition, move your index.html to the root directory and update the script tag accordingly.
<!-- index.html -->
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
Step 4 - Adding vite.config.ts
Create a vite.config.ts file at the root of your project with the following content:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
// https://vitejs.dev/config/
export default defineConfig({
base: '/',
plugins: [react()]
})
Step 5 - Adding vite-env.d.ts
Create a vite-env.d.ts file inside the src folder with the following content:
/// <reference types="vite/client" />
Step 6 - Adding vite scripts
Replace the existing CRA scripts in package.json with Vite scripts.
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"serve": "vite preview"
}
Step 7 - Fixing tsconfig.json
Update your tsconfig.json to its final version.
{
"compilerOptions": {
"target": "ESNext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"jsx": "react-jsx",
"types": ["vite/client", "vite-plugin-svgr/client"]
},
"include": ["src"]
}
Step 8 - Migrating from Jest to Vitest
As we are moving to Vite, another good idea is to consider migrating from Jest to Vitest as well. Here are the steps:
8.1 - Install Vitest dependencies:
npm i -D jsdom vitest @vitest/coverage-v8
8.2 - Update vite.config.ts to include Vitest configurations:
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react-swc'
// https://vitejs.dev/config/
export default defineConfig({
base: '/',
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/setupTests.ts',
css: true,
reporters: ['verbose'],
coverage: {
reporter: ['text', 'json', 'html'],
include: ['src/**/*'],
exclude: [],
}
},
})
8.3 - Update package.json with Vitest scripts:
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"serve": "vite preview",
"test": "vitest",
"test:coverage": "vitest run --coverage --watch=false"
},
Step 9 - Extras
If you use GitHub Actions to push your code to GitHub Pages, you'll need to update the workflow file as Vite generates a dist
folder when we run npm run build
.
name: GitHub Pages
on:
push:
branches:
- master
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: "16"
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/master'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
With these steps, you should now have successfully migrated your create-react-app project to Vite, enjoying its benefits and optimizing your development process for smaller projects. Happy coding!
Top comments (11)
Thank you for a great write-up! This helped a lot for converting over a fairly large React app.
That being said, there were a few "gotchas" I encountered that were not mentioned. Like in a few other comments, I had to remove all occurrences of
%PUBLIC_URL%
from the index.html file. I had to convert over about 95% of my .js files to .jsx. I was having an issue importing a.m4v
video file into a couple of my components. I learned I had to add this 'assetsInclude' line to vite.config.ts:export default defineConfig({
assetsInclude: ['**/*.m4v'],
...
Lastly, I had to rename my env vars in my .env file from
REACT_APP_ABC
toVITE_ABC
and then wherever I used them in my code I had to changeprocess.env.REACT_APP_ABC
toimport.meta.env.VITE_ABC
. Also remember the current running environment(production, development, etc) is now atimport.meta.env.MODE
.for bigger codebase where you dont want to convert all the files from .js to .jsx at once, then this may help:
github.com/vitejs/vite/discussions...
Well done 👍
Nice article, I followed this and got an Internal URI malformed error on the browser. then on the terminal I got that I have to rename every file in my project that uses jsx to a .jsx extension and I am trying to migrate a larger codebase with tons of files. Please any help?
You only need to remove the %PUBLIC_URL% in the index.html file. It worked for me :)
I replaced %PUBLIC_URL% to public. E.g.
<link rel="icon" href="/public/favicon.ico" />
It works now.
Nice work!
If you want to keep index.html under src, you could also create the vite.config.ts under src and change the start script in step 6 to
vite serve src
to serve the code from an alternate directory.X [ERROR] Using a string as a module namespace identifier name is not supported in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)
I am getting this error, can someone help me to fix this error. I appreciate every responses.
Great guide, thanks!
However, I needed 2 more changes to make my app work (our service is served as a framework in our company's platform):
I have done all above mantioned steps but got this error
$ npm start
node:internal/modules/cjs/loader:1327
return process.dlopen(module, path.toNamespacedPath(filename));
^
Error: The specified module could not be found.
\?\D:\My Folder (AITC OFFICE)\aitc-admin-panel\node_modules\@rollup\rollup-win32-x64-msvc\rollup.win32-x64-msvc.node
at Module._extensions..node (node:internal/modules/cjs/loader:1327:18)
at Module.load (node:internal/modules/cjs/loader:1091:32)
at Module._load (node:internal/modules/cjs/loader:938:12)
at Module.require (node:internal/modules/cjs/loader:1115:19)
at require (node:internal/modules/helpers:130:18)
at Object. (D:\My Folder (AITC OFFICE)\aitc-admin-panel\node_modules\rollup\dist\native.js:60:48)
at Module._compile (node:internal/modules/cjs/loader:1241:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
at Module.load (node:internal/modules/cjs/loader:1091:32)
at Module._load (node:internal/modules/cjs/loader:938:12) {
code: 'ERR_DLOPEN_FAILED'
}
Node.js v20.9.0
if you have a bigger codebase and dont want to convert all the files from .js to .jsx at once, then this may help: github.com/vitejs/vite/discussions...